import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
from scipy.optimize import fsolve
from sklearn.metrics import r2_score
# 设置中文字体
try:
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
except:
    plt.rcParams['font.sans-serif'] = ['SimHei', 'SimSun', 'NSimSun', 'FangSong', 'KaiTi']

plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 数据
x = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2])  # 出价
y = np.array([100, 190, 189, 230, 300, 400, 460, 500, 535, 600, 610, 615])  # 结果展现

# 选择多项式的阶数，使用四次多项式
degree = 4
coefficients = np.polyfit(x, y, degree)


polynomial = np.poly1d(coefficients)

# 计算预测值
y_pred = polynomial(x)

# 计算 R^2 值
r2 = r2_score(y, y_pred)

print(f"多项式系数: {coefficients}")
print(f"R^2 值: {r2:.4f}")


# 生成拟合的多项式函数
polynomial = np.poly1d(coefficients)

# 打印拟合方程
print(f"原函数拟合方程: y = {polynomial}")

# 计算导函数
derivative = polynomial.deriv()
print(f"导函数: y' = {derivative}")

# 计算二阶导函数
second_derivative = derivative.deriv()
print(f"二阶导函数: y'' = {second_derivative}")

# 计算三阶导函数
third_derivative = second_derivative.deriv()

# 使用fsolve求解二阶导数的零点
initial_guess = 0.5  # 初始猜测值，可以根据数据范围调整
critical_points = fsolve(second_derivative, initial_guess)

print(f"使二阶导数为0的变量值: x = {critical_points[0]:.4f}")

initial_guess = 0.8  # 初始猜测值，可以根据数据范围调整

def equation_one(x):
    return derivative(x) - 500
inflection_point = fsolve(equation_one, initial_guess)

print(f"使二阶导数为1的变量值: x = {inflection_point[0]:.4f}")


select_points = []
for i in inflection_point:
    y_value = polynomial(i)
    select_points.append((i, y_value))
    print(f"在选择点 x = {i:.4f} 处，函数的值为 y = {y_value:.4f}")


# 找出导函数的极大值点
max_points = []
for point in critical_points:
    if third_derivative(point) < 0:
        y_value = derivative(point)
        select_points.append((point, polynomial(point)))
        max_points.append((point, y_value))
        print(f"在 x = {point:.4f} 处，导函数的值为 y' = {y_value:.4f}")

# 如果找到多个极大值点，选择函数值最大的那个
if max_points:
    max_point, max_value = max(max_points, key=lambda x: x[1])
    print(f"\n导函数的极大值点:")
    print(f"x = {max_point:.4f}")
    print(f"y' = {max_value:.4f}")
else:
    print("\n导函数没有极大值点")
    max_point, max_value = None, None

# 绘图
plt.figure(figsize=(12, 6))

# 绘制原函数
plt.subplot(121)
plt.scatter(x, y, label='原始数据')
x_smooth = np.linspace(x.min(), x.max(), 200)

plt.plot(x_smooth, polynomial(x_smooth), color='red', label='拟合曲线')
# 绘制出选择点

if select_points is not None:
    for point in select_points:
        plt.scatter(point[0],point[1],color='green', label="选择点")
    # plt.scatter(0.668,426,'blue', label="xx",s=100)
plt.xlabel('出价')
plt.ylabel('结果')
plt.title('原函数拟合')
plt.legend()
plt.grid(True)

# 绘制导函数
plt.subplot(122)
plt.plot(x_smooth, derivative(x_smooth), color='blue', label='导函数')
if max_point is not None:
    plt.plot(max_point, max_value, 'ro', label='极大值点')
plt.xlabel('出价')
plt.ylabel('导数值')
plt.title('导函数及其极大值点')
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()